using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace ReactiveGameDemo
{
    public class Manager : Microsoft.Xna.Framework.GameComponent
    {
        Keys[] oldKeyDowns;

        public Manager(Game game) : base(game)
        {
            game.Components.Add(this);
        }

        public override void  Initialize()
        {
             oldKeyDowns = Keyboard.GetState().GetPressedKeys();
 	         base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            // user input
            Keys[] newKeyDowns = Keyboard.GetState().GetPressedKeys();

            IEnumerable<Keys> keyStillDowns = newKeyDowns.Intersect(oldKeyDowns);
            IEnumerable<Keys> keyPresses = newKeyDowns.Except(keyStillDowns);
            IEnumerable<Keys> keyReleases = oldKeyDowns.Except(keyStillDowns);

            foreach (Keys key in keyPresses) GameObject.keyPresses.OnNext(key);
            foreach (Keys key in keyReleases) GameObject.keyReleases.OnNext(key);

            oldKeyDowns = newKeyDowns;

            // collision
            foreach (GameComponent component in Game.Components)
                if(component is GameObject)
                {
                    GameObject gameObject = (GameObject)component;
                    List<GameObject> tmpCollidingWith = gameObject.wasCollidingWith;
                    gameObject.wasCollidingWith = gameObject.isCollidingWith;
                    gameObject.isCollidingWith = tmpCollidingWith;

                    gameObject.isCollidingWith.Clear();
                }
            for (int i = 0; i < Game.Components.Count; i++)
                for (int j = i + 1; j < Game.Components.Count; j++)
                    if (Game.Components[i] is GameObject && Game.Components[j] is GameObject)
                    {
                        GameObject one = (GameObject)Game.Components[i];
                        GameObject another = (GameObject)Game.Components[j];
                        if (Vector2.Distance(one.position, another.position) <= one.size + another.size)
                        {
                            one.isCollidingWith.Add(another);
                            another.isCollidingWith.Add(one);
                        }
                    }
            for (int i=0;i<Game.Components.Count;i++)
                if (Game.Components[i] is GameObject)
                {
                    GameObject gameObject = (GameObject)Game.Components[i];
                    IEnumerable<GameObject> collisionStill = gameObject.isCollidingWith.Intersect(gameObject.wasCollidingWith);
                    IEnumerable<GameObject> collisionEnter = gameObject.isCollidingWith.Except(collisionStill);
                    IEnumerable<GameObject> collisionExit = gameObject.wasCollidingWith.Except(collisionStill);

                    foreach (GameObject other in collisionEnter) gameObject.collisionEnter.OnNext(other);
                    foreach (GameObject other in collisionExit) gameObject.collisionExit.OnNext(other);
                }

            base.Update(gameTime);
        }
    }
}
